package com.bsg.upm.service;

import java.text.MessageFormat;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.bsg.upm.check.CheckResult;
import com.bsg.upm.check.NetworkingCheck;
import com.bsg.upm.constant.DictTypeConstants;
import com.bsg.upm.constant.OperateDictConstants;
import com.bsg.upm.constant.OperateDictTypeConstants;
import com.bsg.upm.constant.SysConstants;
import com.bsg.upm.dto.NetworkingDto;
import com.bsg.upm.entity.ClusterEntity;
import com.bsg.upm.entity.NetworkingEntity;
import com.bsg.upm.entity.SiteEntity;
import com.bsg.upm.entity.UserEntity;
import com.bsg.upm.exception.APIException;
import com.bsg.upm.http.RespJson;
import com.bsg.upm.http.RespJsonFactory;
import com.bsg.upm.util.DateUtils;
import com.bsg.upm.util.PrimaryKeyUtils;

/**
 * 网段管理业务处理类
 * 
 * @author HCK
 *
 */
@Service
public class NetworkingService extends BaseService {

	@Resource
	private NetworkingCheck networkingCheck;

	/**
	 * 网段查询
	 * 
	 * @param paramMap
	 *            请求参数
	 * @return RespJson请求结果对象
	 * @throws APIException
	 *             API异常处理类
	 */
	public RespJson list(Map<String, Object> paramMap) throws APIException {
		try {
			JSONArray results = new JSONArray();

			// 获取指定条件的网段
			List<NetworkingEntity> networkings = networkingDao.list(paramMap);
			if (networkings.size() > 0) {
				// 站点
				String siteId = (String) paramMap.get("siteId");

				// 从MGM获取网段信息
				JSONArray mgmNetworkingInfos = listNetworkingInfoFromMGM(siteId);

				for (NetworkingEntity networking : networkings) {
					// 获取指定的网段信息(来源MGM)
					JSONObject mgmNetworkingInfo = findNetworkingInfoFromMGM(mgmNetworkingInfos, networking.getId());

					// 构建网段展示对象
					NetworkingDto networkingDto = buildShowDto(networking, false, mgmNetworkingInfo);
					results.add(networkingDto);
				}
			}

			return RespJsonFactory.buildOK(results);
		} catch (Exception e) {
			logger.error("网段查询异常", e);
			throw new APIException("网段查询异常");
		}
	}

	/**
	 * 网段详情
	 * 
	 * @param networkingId
	 *            网段编码
	 * @return RespJson请求结果对象
	 * @throws APIException
	 *             API异常处理类
	 */
	public RespJson get(String networkingId) throws APIException {
		try {
			// 获取指定的网段
			NetworkingEntity networking = networkingDao.get(networkingId);

			if (networking == null) {
				return RespJsonFactory.build(HttpStatus.SC_GONE, "该网段不存在");
			}

			// 站点
			String siteId = networking.getSite().getId();

			// 从MGM获取指定的网段信息
			JSONObject mgmNetworkingInfo = getNetworkingInfoFromMGM(siteId, networking.getId());

			// 构建网段展示对象
			NetworkingDto networkingDto = buildShowDto(networking, true, mgmNetworkingInfo);

			return RespJsonFactory.buildOK(networkingDto);
		} catch (Exception e) {
			logger.error("网段获取异常", e);
			throw new APIException("网段获取异常");
		}
	}

	/**
	 * 网段新增
	 * 
	 * @param paramMap
	 *            请求参数
	 * @return RespJson请求结果对象
	 * @throws APIException
	 *             API异常处理类
	 */
	@Transactional(rollbackFor = APIException.class)
	public RespJson save(Map<String, Object> paramMap) throws APIException {
		// 操作动作
		String operateAcion = OperateDictConstants.ACTION_ADD;
		String operateAcionText = dictTypeCache.getTextFromCache(OperateDictTypeConstants.OPERATE_ACTION, operateAcion);
		try {
			// 网段新增检查
			CheckResult chkRS = networkingCheck.checkSave(paramMap);
			if (chkRS.isError()) {
				return RespJsonFactory.build(chkRS.getStatus(), chkRS.getErrorMsg());
			}

			// 构建网段对象
			NetworkingEntity networking = buildNetworking(paramMap);
			networkingDao.save(networking);

			// 站点
			String siteId = networking.getSite().getId();
			// 向MGM注册网段信息
			saveNetworkingToMGM(siteId, networking);

			// 保存操作日志
			saveOperateLog(OperateDictConstants.MODEL_NETWORKING, operateAcion, networking.getId(),
					networking.getName(), networking.getCreateDateTime());

			return RespJsonFactory.buildCreated();
		} catch (Exception e) {
			logger.error("网段" + operateAcionText + "异常", e);
			throw new APIException("网段" + operateAcionText + "异常");
		}
	}

	/**
	 * 网段编辑
	 * 
	 * @param paramMap
	 *            请求参数
	 * @return RespJson请求结果对象
	 * @throws APIException
	 *             API异常处理类
	 */
	@Transactional(rollbackFor = APIException.class)
	public RespJson update(Map<String, Object> paramMap) throws APIException {
		// 操作动作
		String operateAcion = OperateDictConstants.ACTION_UPDATE;
		String operateAcionText = dictTypeCache.getTextFromCache(OperateDictTypeConstants.OPERATE_ACTION, operateAcion);
		try {
			// 网段编辑检查
			CheckResult chkRS = networkingCheck.checkUpdate(paramMap);
			if (chkRS.isError()) {
				return RespJsonFactory.build(chkRS.getStatus(), chkRS.getErrorMsg());
			}

			// 构建网段对象
			NetworkingEntity networking = buildNetworkingToUpdate(paramMap);
			networkingDao.update(networking);

			// 保存操作日志
			saveOperateLog(OperateDictConstants.MODEL_NETWORKING, operateAcion, networking.getId(),
					networking.getName());

			return RespJsonFactory.buildOK();
		} catch (Exception e) {
			logger.error("网段" + operateAcionText + "异常", e);
			throw new APIException("网段" + operateAcionText + "异常");
		}
	}

	/**
	 * 网段启用/停用
	 * 
	 * @param id
	 *            网段编码
	 * @param enable
	 *            是否启用
	 * @return RespJson请求结果对象
	 * @throws APIException
	 *             API异常处理类
	 */
	@Transactional(rollbackFor = APIException.class)
	public RespJson enable(String id, boolean enable) throws APIException {
		// 操作动作
		String operateAcion = OperateDictConstants.ACTION_DISABLE;
		if (enable) {
			operateAcion = OperateDictConstants.ACTION_ENABLE;
		}
		String operateAcionText = dictTypeCache.getTextFromCache(OperateDictTypeConstants.OPERATE_ACTION, operateAcion);
		try {
			// 获取指定的网段
			NetworkingEntity networking = networkingDao.get(id);

			// 网段启停检查
			CheckResult chkRS = null;
			if (enable) {
				chkRS = networkingCheck.checkEnable(networking);
			} else {
				chkRS = networkingCheck.checkDisable(networking);
			}
			if (chkRS.isError()) {
				return RespJsonFactory.build(chkRS.getStatus(), chkRS.getErrorMsg());
			}

			// 设置启停状态
			networking.setEnabled(enable);
			networkingDao.updateEnabled(networking);

			// 保存操作日志
			saveOperateLog(OperateDictConstants.MODEL_NETWORKING, operateAcion, networking.getId(),
					networking.getName());

			return RespJsonFactory.buildOK();
		} catch (Exception e) {
			logger.error("网段" + operateAcionText + "异常", e);
			throw new APIException("网段" + operateAcionText + "异常");
		}
	}

	/**
	 * 网段删除
	 * 
	 * @param id
	 *            网段编码
	 * @return RespJson请求结果对象
	 * @throws APIException
	 *             API异常处理类
	 */
	@Transactional(rollbackFor = APIException.class)
	public RespJson remove(String id) throws APIException {
		// 操作动作
		String operateAcion = OperateDictConstants.ACTION_REMOVE;
		String operateAcionText = dictTypeCache.getTextFromCache(OperateDictTypeConstants.OPERATE_ACTION, operateAcion);
		try {
			// 获取指定的网段
			NetworkingEntity networking = networkingDao.get(id);

			// 网段删除检查
			CheckResult chkRS = networkingCheck.checkRemove(networking);
			if (chkRS.isError()) {
				return RespJsonFactory.build(chkRS.getStatus(), chkRS.getErrorMsg());
			}

			networkingDao.remove(id);

			// 站点
			String siteId = networking.getSite().getId();
			// 删除MGM上的网段信息
			removeNetworkingFromMGM(siteId, networking.getId());

			// 保存操作日志
			saveOperateLog(OperateDictConstants.MODEL_NETWORKING, operateAcion, networking.getId(),
					networking.getName());

			return RespJsonFactory.buildNoContent();
		} catch (Exception e) {
			logger.error("网段" + operateAcionText + "异常", e);
			throw new APIException("网段" + operateAcionText + "异常");
		}
	}

	/**
	 * 从MGM上获取网段信息
	 * 
	 * @param siteId
	 *            站点编码
	 * @return MGM网段信息集合
	 * @throws APIException
	 *             API异常处理类
	 */
	private JSONArray listNetworkingInfoFromMGM(String siteId) throws APIException {
		String urlPattern = "/{0}/networkings";
		String url = MessageFormat.format(urlPattern, SysConstants.MGM_VERSION);
		RespJson httpRespJson = sendHttpGet(siteId, SysConstants.INTERFACE_TYPE_MGM, url);
		if (httpRespJson.getStatus() == HttpStatus.SC_OK) {
			return ((JSONArray) httpRespJson.getData());
		} else {
			throw new APIException(httpRespJson.getMsg());
		}
	}

	/**
	 * 从网段列表中获取指定的网段
	 * 
	 * @param mgmNetworkingInfos
	 *            MGM网段信息集合
	 * @param networkingId
	 *            网段编码
	 * @return JSONObject MGM网段信息
	 */
	private JSONObject findNetworkingInfoFromMGM(JSONArray mgmNetworkingInfos, String networkingId) {
		if (mgmNetworkingInfos == null) {
			return null;
		}
		for (int i = 0; i < mgmNetworkingInfos.size(); i++) {
			JSONObject jsonObject = mgmNetworkingInfos.getJSONObject(i);
			if (jsonObject.getString("networking_id").equals(networkingId)) {
				return jsonObject;
			}
		}
		return null;
	}

	/**
	 * 从MGM上获取指定的网段
	 * 
	 * @param siteId
	 *            站点编码
	 * @param networkingId
	 *            网段编码
	 * @return MGM网段信息
	 * @throws APIException
	 *             API异常处理类
	 */
	public JSONObject getNetworkingInfoFromMGM(String siteId, String networkingId) throws APIException {
		String urlPattern = "/{0}/networkings/{1}";
		String url = MessageFormat.format(urlPattern, SysConstants.MGM_VERSION, networkingId);
		RespJson httpRespJson = sendHttpGet(siteId, SysConstants.INTERFACE_TYPE_MGM, url);
		if (httpRespJson.getStatus() == HttpStatus.SC_OK) {
			return ((JSONObject) httpRespJson.getData());
		} else {
			throw new APIException(httpRespJson.getMsg());
		}
	}

	/**
	 * 向MGM注册网段信息
	 * 
	 * @param siteId
	 *            站点编码
	 * @param networking
	 *            网段
	 * @return JSONObject 操作结果
	 * @throws APIException
	 *             API异常处理类
	 */
	private JSONObject saveNetworkingToMGM(String siteId, NetworkingEntity networking) throws APIException {
		JSONObject param = new JSONObject();
		param.put("start", networking.getStartIp());
		param.put("end", networking.getEndIp());
		param.put("prefix", networking.getPrefix());
		param.put("gateway", networking.getGateway());
		param.put("vlan_id", networking.getVlanId());

		String urlPattern = "/{0}/networkings/{1}/ips";
		String url = MessageFormat.format(urlPattern, SysConstants.MGM_VERSION, networking.getId());
		RespJson httpRespJson = sendHttpPost(siteId, SysConstants.INTERFACE_TYPE_MGM, url, param.toJSONString());
		if (httpRespJson.getStatus() != HttpStatus.SC_CREATED) {
			throw new APIException(httpRespJson.getMsg());
		}
		return (JSONObject) httpRespJson.getData();
	}

	/**
	 * 从MGM上删除网段信息
	 * 
	 * @param siteId
	 *            站点编码
	 * @param networkingId
	 *            网段编码
	 * @throws APIException
	 *             API异常处理类
	 */
	private void removeNetworkingFromMGM(String siteId, String networkingId) throws APIException {
		String urlPattern = "/{0}/networkings/{1}/ips";
		String url = MessageFormat.format(urlPattern, SysConstants.MGM_VERSION, networkingId);
		RespJson httpRespJson = sendHttpDelete(siteId, SysConstants.INTERFACE_TYPE_MGM, url);
		if (httpRespJson.getStatus() != HttpStatus.SC_NO_CONTENT) {
			throw new APIException(httpRespJson.getMsg());
		}
	}

	/**
	 * 从MGM网段信息中获取IP总数
	 * 
	 * @param mgmNetworkingInfo
	 *            MGM网段信息
	 * @return IP总数
	 */
	private int countIp(JSONObject mgmNetworkingInfo) {
		int ipCount = 0;
		if (mgmNetworkingInfo != null) {
			JSONArray ipJsonArr = mgmNetworkingInfo.getJSONArray("IPs");
			if (ipJsonArr != null) {
				ipCount = ipJsonArr.size();
			}
		}
		return ipCount;
	}

	/**
	 * 从MGM网段信息中获取IP使用数
	 * 
	 * @param mgmNetworkingInfo
	 *            MGM网段信息
	 * @return IP使用数
	 */
	private int countUsedIp(JSONObject mgmNetworkingInfo) {
		int ipUsedCount = 0;
		if (mgmNetworkingInfo != null) {
			JSONArray ipJsonArr = mgmNetworkingInfo.getJSONArray("IPs");
			if (ipJsonArr != null) {
				for (int i = 0; i < ipJsonArr.size(); i++) {
					if (StringUtils.isNotBlank(ipJsonArr.getJSONObject(i).getString("unit_id"))) {
						ipUsedCount++;
					}
				}
			}
		}
		return ipUsedCount;
	}

	/**
	 * 构建网段展示独享
	 * 
	 * @param networking
	 *            网段对象
	 * @param showDetail
	 *            是否展示详情
	 * @param mgmNetworkingInfo
	 *            MGM网段信息
	 * @return 网段展示对象
	 */
	private NetworkingDto buildShowDto(NetworkingEntity networking, boolean showDetail, JSONObject mgmNetworkingInfo) {
		NetworkingDto networkingDto = new NetworkingDto();
		SiteEntity site = networking.getSite();
		networkingDto.setSiteId(site.getId());
		networkingDto.setSiteName(site.getName());
		networkingDto.setId(networking.getId());
		networkingDto.setName(networking.getName());
		networkingDto.setStartIp(networking.getStartIp());
		networkingDto.setEndIp(networking.getEndIp());
		networkingDto.setVlanId(String.valueOf(networking.getVlanId()));
		networkingDto.setPrefix(String.valueOf(networking.getPrefix()));
		networkingDto.setGateway(networking.getGateway());
		int ipCount = countIp(mgmNetworkingInfo);
		networkingDto.setIpCount(ipCount);
		if (ipCount != 0) {
			networkingDto.setIpUsedCount(countUsedIp(mgmNetworkingInfo));
		}
		networkingDto.setEnabled(networking.getEnabled());
		networkingDto.setEnabledText(dictTypeCache.getTextFromCache(DictTypeConstants.STATUS_ENABLED,
				String.valueOf(networking.getEnabled())));
		ClusterEntity cluster = networking.getCluster();
		if (cluster != null) {
			networkingDto.setClusterId(cluster.getId());
			networkingDto.setClusterName(cluster.getName());
			networkingDto.setAreaId(cluster.getArea().getId());
			networkingDto.setAreaName(cluster.getArea().getName());
		}
		networkingDto.setDescription(networking.getDescription());
		networkingDto.setCreateDateTime(DateUtils.dateTimeToString(networking.getCreateDateTime()));
		networkingDto.setCreateLoginUserName(networking.getCreateUserLoginName());
		return networkingDto;
	}

	/**
	 * 构建网段对象
	 * 
	 * @param paramMap
	 *            请求参数
	 * @return 网段对象
	 */
	private NetworkingEntity buildNetworking(Map<String, Object> paramMap) {
		NetworkingEntity networking = new NetworkingEntity();
		networking.setId(PrimaryKeyUtils.uniqueId());
		SiteEntity site = new SiteEntity();
		site.setId((String) paramMap.get("site"));
		networking.setSite(site);
		networking.setName(StringUtils.trim((String) paramMap.get("name")));
		networking.setStartIp(StringUtils.trim((String) paramMap.get("startIp")));
		networking.setEndIp(StringUtils.trim((String) paramMap.get("endIp")));
		networking.setPrefix((Integer) paramMap.get("prefix"));
		networking.setGateway(StringUtils.trim((String) paramMap.get("gateway")));
		networking.setVlanId((Integer) paramMap.get("vlanId"));
		networking.setEnabled(true);
		if (paramMap.containsKey("description")) {
			networking.setDescription(StringUtils.trim((String) paramMap.get("description")));
		}
		networking.setCreateDateTime(systemDao.getCurrentDateTime());
		UserEntity user = getUser();
		String username = user.getUsername();
		networking.setCreateUserLoginName(username);
		return networking;
	}

	/**
	 * 构建网段对象用于更新操作
	 * 
	 * @param paramMap
	 *            请求参数
	 * @return 网段对象
	 */
	private NetworkingEntity buildNetworkingToUpdate(Map<String, Object> paramMap) {
		String networkingId = (String) paramMap.get("networkingId");
		NetworkingEntity networking = networkingDao.get(networkingId);
		if (paramMap.containsKey("name")) {
			networking.setName(StringUtils.trim((String) paramMap.get("name")));
		}

		if (paramMap.containsKey("description")) {
			networking.setDescription(StringUtils.trim((String) paramMap.get("description")));
		}
		return networking;
	}
}
